﻿using System.Globalization;
using System.Windows;
using Avalonia.Data.Converters;
using GraphShape.Algorithms.Layout;
using GraphShape.Controls.Converters;
using GraphShape.Controls.Extensions;
using Point = GraphShape.Point;
using Size = GraphShape.Size;

namespace KinonekoSoftware.Studio.Resources.Converters
{

     /// <summary>
    /// Converter of position and sizes of the source and target points,
    /// and the route information of an edge to a path.
    /// </summary>
    /// <remarks>The edge can bend, or it can be straight line.</remarks>
    public class NoLabelEdgeGenerator : EdgeGenerator, IMultiValueConverter
    {
        #region IMultiValueConverter


        /// <inheritdoc />
        /// <exception cref="T:System.NotSupportedException">This method is not supported.</exception>
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("Path to edge route conversion not supported.");
        }

        #endregion
        
        public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values is null)
                return new PathFigures();

            if (values.Count != 9)
            {
                throw new ArgumentException(
                    $"{nameof(NoLabelEdgeGenerator)} must have 9 parameters: pos (1,2), size (3,4) of source; pos (5,6), size (7,8) of target; routeInformation (9).",
                    nameof(values));
            }

            ExtractInputs(
                values,
                out var sourcePos,
                out var targetPos,
                out var sourceSize,
                out var targetSize,
                out var routeInformation);

            var hasRouteInfo = routeInformation != null && routeInformation.Length > 0;

            // Create the path
            var p1 = LayoutUtils.GetClippingPoint(
                sourceSize,
                sourcePos,
                hasRouteInfo ? routeInformation[0].ToGraphShapePoint() : targetPos).ToPoint();

            var p2 = LayoutUtils.GetClippingPoint(
                targetSize,
                targetPos,
                hasRouteInfo ? routeInformation[^1].ToGraphShapePoint() : sourcePos).ToPoint();


            var segments = new PathSegment[1 + (hasRouteInfo ? routeInformation.Length : 0)];
            if (hasRouteInfo)
            {
                // Append route points
                for (var i = 0; i < routeInformation.Length; ++i)
                {
                    segments[i] = new LineSegment
                    {
                        Point = routeInformation[i],
                    };
                }
            }

            var pLast = hasRouteInfo ? routeInformation[^1] : p1;
            var v     = pLast - p2;
            v = v / GetLength(v) * 5;

            segments[^1] = new LineSegment
            {
                Point = p2 + v,
            };

            var pathCollection = new PathFigures
            {
                new PathFigure
                {
                    StartPoint = p1,
                    Segments = GetSegments(segments),
                    IsClosed = false,
                },
            };

            return pathCollection;
        }
    }
}